/*
 * JosephusGame.cpp
 *
 *  Created on: Oct 1, 2010
 *      Author: Jacob
 */
#include "stdafx.h"
#include "JosephusGame.h"

JosephusGame* JosephusGame::newGameWithNumberOfPeopleAndN(int numberOfPeople,
		int nthPersonToKill)
{
	return new JosephusGame(numberOfPeople, nthPersonToKill);
}

JosephusGame::JosephusGame(int numberOfPeople, int nthPersonToKill)
{
	this->soleSurvivor = false;
	this->numberOfPeople = numberOfPeople;
	this->nthPersonToKill = nthPersonToKill;
	this->prisonersRemovedInRound = 0;
	validateInput();
	createLinkedList();
}

JosephusGame::~JosephusGame()
{
	delete prisoners;
}

void JosephusGame::validateInput()
{
	if (numberOfPeople > 100)
		numberOfPeople = 100;
	else if (numberOfPeople < 1)
		numberOfPeople = 1;

	if (nthPersonToKill > 20)
		nthPersonToKill = 20;
	else if (nthPersonToKill < 1)
		nthPersonToKill = 1;
}

void JosephusGame::createLinkedList()
{
	prisoners = LinkedList::newLinkedList(true);
	prisoners->addToHead("P:1");

	ostringstream stringStream;
	for (int index = 2; index <= numberOfPeople; index++)
	{
		stringStream.str("");
		stringStream << "P:" << index;
		prisoners->addToTail(stringStream.str());
	}

	this->lastCurrent = prisoners->getCurrent();
}

void JosephusGame::play()
{
	char userInput;

	while (!soleSurvivor)
	{
		cout << "\nBegin Round: Y/N?";
		cin >> userInput;
		if (userInput == 'y')
			takeTurn();
	}
}

void JosephusGame::takeTurn()
{
	if (prisoners->getSize() > 1)
	{
		int prisonersToKillThisRound = prisoners->getSize() / nthPersonToKill;
		prisoners->setCurrentToHead();

		for (int turn = 0; turn < prisonersToKillThisRound; turn++)
		{
			killEveryNthPerson();
		}
		removeDeadPrisoners();
	}
	else
	{
		soleSurvivor = true;
		cout << "\nPrisoner: " << prisoners->getCurrent()->getData()
				<< " Has Survived";
	}
}

void JosephusGame::killEveryNthPerson()
{
	for (int index = 1; index <= nthPersonToKill; index++)
	{
		if (index == nthPersonToKill)
		{
			cout << "\nPrisoner: " << prisoners->getCurrent()->getData()
					<< " Has been removed";
			prisoners->getCurrent()->setData("Dead");
			prisonersRemovedInRound++;
		}
		prisoners->iterate();
	}
}

void JosephusGame::removeDeadPrisoners()
{
	int numberOfPrisonersRemoved = 0;

	prisoners->setCurrentToHead();
	while(numberOfPrisonersRemoved != prisonersRemovedInRound)
	{
		if (prisoners->getCurrent()->getData() == "Dead")
		{
			prisoners->remove(prisoners->getCurrent());
			numberOfPrisonersRemoved++;
		}

		prisoners->iterate();
	}

	prisonersRemovedInRound = 0;
}

